<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link rel="stylesheet" href="./js/ol.css">
    <script src="./js/geojson2svg.min.js"></script>
    <script src="./js/ol.js"></script>
    <style>
        html,
        body {
            margin: 0px;
            width: 100%;
            height: 100%;
        }

        #map {
            width: 100%;
            height: 100%;
        }

        .button {
            width: 70px;
            height: 35px;
            text-align: center;
            line-height: 35px;
            position: absolute;
            top: 20px;
            color: #fff;
            right: 20px;
            z-index: 1;
            font-size: 14px;
            background-color: #324bbb;
            border-radius: 10px;
            border: 1px solid #ccc;
        }

        .button:hover {
            background-color: #307dd6;
            cursor: hand;
        }
    </style>
</head>

<body>
    <div class="button" id="exportButton">导出svg</div>
    <div id="map"></div>

    <script>

        var options = {
            mapOptions: {
                target: 'map',
                center: [103.35888369920396, 36.12961334619311],
                projection: 'EPSG:3857',
                zoom: 4
            }
        }

        var Geo2SVGMap = function (options) {
            this.options = options;
            this.defaultStyle = {
                'Point': new ol.style.Style({
                    image: new ol.style.Circle({
                        fill: new ol.style.Fill({
                            color: 'rgba(255,255,0,0.5)'
                        }),
                        radius: 5,
                        stroke: new ol.style.Stroke({
                            color: '#ff0',
                            width: 1
                        })
                    })
                }),
                'LineString': new ol.style.Style({
                    stroke: new ol.style.Stroke({
                        color: '#f00',
                        width: 3
                    })
                }),
                'Polygon': new ol.style.Style({
                    fill: new ol.style.Fill({
                        color: 'rgba(0,255,255,0.5)'
                    }),
                    stroke: new ol.style.Stroke({
                        color: '#0ff',
                        width: 1
                    })
                }),
                'MultiPoint': new ol.style.Style({
                    image: new ol.style.Circle({
                        fill: new ol.style.Fill({
                            color: 'rgba(255,0,255,0.5)'
                        }),
                        radius: 5,
                        stroke: new ol.style.Stroke({
                            color: '#f0f',
                            width: 1
                        })
                    })
                }),
                'MultiLineString': new ol.style.Style({
                    stroke: new ol.style.Stroke({
                        color: '#0f0',
                        width: 3
                    })
                }),
                'MultiPolygon': new ol.style.Style({
                    fill: new ol.style.Fill({
                        color: 'rgba(0,0,255,0.5)'
                    }),
                    stroke: new ol.style.Stroke({
                        color: '#00f',
                        width: 1
                    })
                })
            };
            this.format = new ol.format.GeoJSON();
            this.map = null;
            this.initDropInteraction();
            this.initMap();
            this.createBaseLayer();
            this.initVectorLayer();
            this.bindDropEvent();

        }


        Geo2SVGMap.prototype = {
            initMap: function () {
                var self = this;
                var mapOptions = this.options.mapOptions || {};
                this.map = new ol.Map({
                    interactions: ol.interaction.defaults().extend([self.dragAndDropInteraction]),
                    target: mapOptions.target || 'map',
                    layers: [],
                    view: new ol.View({
                        center: ol.proj.fromLonLat(mapOptions.center || [104, 30]),
                        projection: mapOptions.projection || 'EPSG:3857',
                        zoom: mapOptions.zoom || 5
                    })
                });
                /**
                 * 标注字段
                 **/
                this.labelField = null;
                /**
                 * 属性字段名
                 **/
                this.fields = [];
            },
            /**
             * 初始化拖动交互 
             **/
            initDropInteraction: function () {
                this.dragAndDropInteraction = new ol.interaction.DragAndDrop({
                    formatConstructors: [
                        ol.format.GPX,
                        ol.format.GeoJSON,
                        ol.format.IGC,
                        ol.format.KML,
                        ol.format.TopoJSON
                    ],
                    projection: "EPSG:4326"
                });
            },
            createBaseLayer: function () {
                var source = new ol.source.XYZ({
                    url: 'https://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}',
                    projection: 'EPSG:3857'
                });
                this.baseLayer = new ol.layer.Tile({
                    source: source
                });
                this.map.addLayer(this.baseLayer);
            },
            /**
             * 
             * */
            loadGeoJSON: function () {

            },
            updateStyle: function () {

            },
            showLabel: function (visible) {

            },
            initVectorLayer: function () {
                var self = this;
                this.vectorSource = new ol.source.Vector({
                    projection: "EPSG:3857"
                });

                var styleFunction = function (feature, resolution) {
                    var featureStyleFunction = feature.getStyleFunction();
                    if (featureStyleFunction) {
                        return featureStyleFunction.call(feature, resolution);
                    } else {
                        return self.defaultStyle[feature.getGeometry().getType()];
                    }
                };

                this.vectorLayer = new ol.layer.Vector({
                    source: self.vectorSource,
                    style: styleFunction
                });

                this.map.addLayer(this.vectorLayer);
            },
            bindDropEvent: function () {
                var map = this.map;
                var self = this;
                this.dragAndDropInteraction.on('addfeatures', function (event) {

                    var features = event.features;
                    features.forEach(f => {
                        var g = f.getGeometry();
                        var ng = g.transform('EPSG:4326', 'EPSG:3857');
                        f.setGeometry(g);
                    });


                    self.vectorSource.clear();
                    self.vectorSource.addFeatures(event.features);

                    map.getView().fit(self.vectorSource.getExtent());
                });
            },
            downloadSVG(content) {
                var aTag = document.createElement('a');
                var blob = new Blob([content]);
                aTag.download = +new Date() + '.svg';
                aTag.href = URL.createObjectURL(blob);
                aTag.click();
                URL.revokeObjectURL(blob);
            },
            /**
             * 导出svg
             **/
            exportSVG: function () {
                var self = this;

                var dataExt = self.vectorSource.getExtent();
                var ext = ol.extent.buffer(dataExt, (dataExt[2] - dataExt[0]) / 10)

                var convertor = geojson2svg({
                    viewportSize: { width: 500, height: 500 },
                    attributes: {
                        'style': 'stroke:#006600; fill: #F0F8FF;stroke-width:0.5px;',
                        'vector-effect': 'non-scaling-stroke'
                    },
                    mapExtent: {
                        left: ext[0],
                        right: ext[2],
                        bottom: ext[1],
                        top: ext[3]
                    },
                    explode: false
                });

                var featureObj = this.format.writeFeaturesObject(this.vectorSource.getFeatures());
                var svgElements = convertor.convert(featureObj);

                // 拼接svg名称
                var svgContent = '<svg xmlns="http://www.w3.org/2000/svg" width="500" height="500" x="0" y="0">';
                svgElements.forEach(function (svgStr) {
                    svgContent += svgStr;
                });
                svgContent += '</svg>';

                this.downloadSVG(svgContent);
            }
        };


        var map = new Geo2SVGMap(options);

        var exportButton = document.getElementById('exportButton');
        exportButton.addEventListener('click', function () {

            if (map.vectorSource.getFeatures().length < 1) {
                alert('请拖动数据到地图')
            } else {
                map.exportSVG();
            }
        });
    </script>
</body>

</html>